package com.fintech.pangu.autoconfigure.security;

import com.fintech.pangu.autoconfigure.security.properties.PanGuSecurityProperties;
import com.fintech.pangu.security.PanGuWebSecurityConfiguration;
import com.fintech.pangu.security.authorize.AuthorizeConfigManager;
import com.fintech.pangu.security.authorize.impl.DefaultAuthorizeConfigManager;
import com.fintech.pangu.security.config.PanGuAuthenticationManagerBuilderManager;
import com.fintech.pangu.security.config.PanGuHttpSecurityManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * PanGu安全配置适配器类
 * 继承PanGuWebSecurityConfiguration安全基类，其继承了spring WebSecurityConfigurerAdapter
 * 1、将PanGuSecurityProperties的配置项转化为安全基类的配置方法
 */
public class PanGuWebSecurityConfigurationAdapter extends PanGuWebSecurityConfiguration {

    /**
     * pangu所有安全属性
     */
    private PanGuSecurityProperties panGuSecurityProperties;

    private PasswordEncoder passwordEncoder;

    /**
     * 盘古微服务授权配置管理器
     */
    private AuthorizeConfigManager authorizeConfigManager;

    /**
     * 盘古微服务HttpSecurity配置管理器
     */
    private PanGuHttpSecurityManager panGuHttpSecurityManager;

    /**
     * 盘古微服务AuthenticationManagerBuilderManager配置管理器
     */
    private PanGuAuthenticationManagerBuilderManager panGuAuthenticationManagerBuilderManager;


    /**
     * 子类通过构造方法传入PanGuSecurityProperties
     * @param panGuSecurityProperties
     */
    public PanGuWebSecurityConfigurationAdapter(
            PanGuSecurityProperties panGuSecurityProperties,
            PasswordEncoder passwordEncoder,
            PanGuHttpSecurityManager panGuHttpSecurityManager,
            AuthorizeConfigManager authorizeConfigManager,
            PanGuAuthenticationManagerBuilderManager panGuAuthenticationManagerBuilderManager) {
        this.panGuSecurityProperties = panGuSecurityProperties;
        this.passwordEncoder = passwordEncoder;
        this.panGuHttpSecurityManager = panGuHttpSecurityManager;
        this.authorizeConfigManager = authorizeConfigManager;
        this.panGuAuthenticationManagerBuilderManager = panGuAuthenticationManagerBuilderManager;
    }



    /**
     * 是否开启csrf
     * @return
     */
    @Override
    protected boolean enableCsrf() {
        return panGuSecurityProperties.getHttp().getCsrf().isEnable();
    }

    /**
     * 是否开启cors
     * @return
     */
    @Override
    protected boolean enableCors() {
        if(StringUtils.hasText(panGuSecurityProperties.getHttp().getCors().getPath())){
            return true;
        }
        return false;
    }

    /**
     * 实现配置CorsConfigurationSource逻辑
     * @return
     */
    @Override
    protected CorsConfigurationSource corsConfigurationSource() {
        // 如果启用了cors
        if(enableCors()){
            // 配置CorsConfigurationSource
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.setAllowedHeaders(panGuSecurityProperties.getHttp().getCors().getAllowedHeaders());
            corsConfiguration.setAllowedMethods(panGuSecurityProperties.getHttp().getCors().getAllowedMethods());
            corsConfiguration.setAllowedOrigins(panGuSecurityProperties.getHttp().getCors().getAllowedOrigins());
            corsConfiguration.setAllowCredentials(panGuSecurityProperties.getHttp().getCors().isAllowCredentials());

            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration(panGuSecurityProperties.getHttp().getCors().getPath(), corsConfiguration);
            return source;
        }
        return null;
    }


    /**
     * 是否开启headers frameOptions
     * @return
     */
    @Override
    protected boolean enableFrameOptions() {
        return panGuSecurityProperties.getHttp().getHeaders().getFrameOptions().isEnable();
    }

    /**
     * 是否无状态
     * 逻辑：如果认证token类型为jwt即为无状态
     * @return
     */
    @Override
    protected boolean isStateless() {
        boolean jwtTokenPresent =  ClassUtils.isPresent("com.fintech.pangu.security.jwt.provider.authentication.token.JwtAuthenticationTokenServices",
                PanGuWebSecurityConfigurationAdapter.class.getClassLoader());

        // 先胖有没有JWT Token相关类
        if(!jwtTokenPresent){
            return false;
        }

        // 再判断是否配置了jwt签名密匙
        return StringUtils.hasText(panGuSecurityProperties.getAuthentication().getToken().getJwt().getSecret()) ? true : false;
    }

    /**
     * 配置完全不经过spring security filter的路径列表
     * @return
     */
    @Override
    protected List<String> ignoringUrls(){
        List<String> ignoringUrls = new ArrayList<>();

        // 默认排除路径
        ignoringUrls.addAll(Arrays.asList(panGuSecurityProperties.getWeb().getDefaultIgnoringUrls()));

        // 自定义排除的路径
        if (!ObjectUtils.isEmpty(panGuSecurityProperties.getWeb().getIgnoringUrls())) {
            ignoringUrls.addAll(Arrays.asList(panGuSecurityProperties.getWeb().getIgnoringUrls()));
        }

        return ignoringUrls;
    }



    @Override
    protected AuthorizeConfigManager getAuthorizeConfigManager() {
        return ObjectUtils.isEmpty(this.authorizeConfigManager) ? new DefaultAuthorizeConfigManager() : this.authorizeConfigManager;
    }

    @Override
    protected PanGuHttpSecurityManager getPanGuHttpSecurityManager() {
        return ObjectUtils.isEmpty(this.panGuHttpSecurityManager) ? new PanGuHttpSecurityManager() : this.panGuHttpSecurityManager;
    }

    @Override
    protected PanGuAuthenticationManagerBuilderManager getPanGuAuthenticationManagerBuilderManager() {
        return ObjectUtils.isEmpty(this.panGuAuthenticationManagerBuilderManager) ? new PanGuAuthenticationManagerBuilderManager() : this.panGuAuthenticationManagerBuilderManager;
    }

    @Override
    protected PasswordEncoder getPasswordEncoder() {
        return ObjectUtils.isEmpty(this.passwordEncoder) ? new BCryptPasswordEncoder() : this.passwordEncoder;
    }

}
